import Zhi from '../bagua/zhi.js'
import Gan from '../bagua/gan.js'
import TaiyiGround from '../bagua/taiyiGround.js'
import Base from '../bagua/base.js'

import BaseStage from './baseStage.js'

import dictionary from '../bagua/dictionary.js'

// 中5宫的索引，用于寄宫
const CENTER_PALACE_INDEX = 4
// 乾1宫的索引，用于寄宫
const EXTRA_PALACE_INDEX = 8

// 太乙天盘神煞
const taiyiSkyList = ['太乙', '文昌', '主大将', '主参将', '计神', '始击', '客大将', '客参将', '四神', '天乙', '地乙', '飞符', '五福', '小游', '君基', '臣基', '民基']
// 太乙天盘神煞简称
const taiyiSkySimList = ['太乙', '文昌', '主大', '主参', '计神', '始击', '客大', '客参', '四神', '天乙', '地乙', '飞符', '五福', '小游', '君基', '臣基', '民基']
// const taiyiSkySimList = ['乙', '文', '主大', '主参', '计', '始', '客大', '客参', '四', '天', '地', '飞', '福', '游', '君', '臣', '民']
// 太乙天盘神煞五行
const taiyiSkyWuxingList = [0, 2, 3, 4, 2, 1, 4, 0, 4, 3, 2, 1, 2, 0, 2, 2, 2]
// 0代表阴，1代表阳，太乙天盘神煞阴阳表
const taiyiSkyYinyangList = [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0]

class Taiyi extends BaseStage {
  constructor (options = {}) {
    super(options)
    
    this.initTaiyi()
  }
  
  initTaiyi () {
    this.types.push('Taiyi')
  }
  
  /* @section static静态方法 */
  /*
    计算太乙积数
    ganzhiRange代表用当下时间干支的几柱来计算太乙积数，默认为时局，即四柱
  */
  static countTaiyiNum (stage, ganzhiRange = 3) {
    let index = ganzhiRange
    
    let count = 0
    let mutiCount = 1
    for (let i = 0; i <= index; i++) {
      let num = 0
      if (i === 1) {
        // 月柱加农历月月建
        num = stage.date.lunarMonthSign
      }
      else if (i === 2) {
        // 日柱加农历日数
        num = stage.date.lunarDayIndex + 1
      }
      else {
        // 其他情况都是加地支序数
        num = stage.date.ganzhi[i].zhi.index + 1
      }
      count = count + num
      mutiCount = mutiCount * (stage.date.ganzhi[i].index + 1)
    }
    
    stage.taiyiNum = count + mutiCount
  }
  
  /*
    排布太乙
    排布方法：
    1. 积数 / 24 = 轮数 ...... 1余
    2. 1式余数作为被除数继续除3，1余 / 3 = 商 ...... 余
    2. 所走宫数为 商 + 1 , 入宫年数为 余
    3. 移动方式：阳局从乾1宫起，阴局从巽9宫起，阳顺阴逆，顺加逆减，按照宫位数增减进行跳宫。当遇到中5宫时，跳过。
    4. 每宫停留3年，第一年理天，第二年理地，第三年理人，一共8个宫，故一圈共24年。
  */
  static setTaiyi (stage) {    
    // 阴阳局数
    const isSolar = stage.isSolar
    
    // 太乙除数
    const TAIYI_DIVIDER = 24
    // 太乙入宫年数
    const TAIYI_DURATION = 3
    
    const taiyiLeft = stage.taiyiNum % TAIYI_DIVIDER === 0 ? TAIYI_DIVIDER : stage.taiyiNum % TAIYI_DIVIDER
    // 移动宫数向上取整
    const palacesNum = Math.ceil(taiyiLeft / TAIYI_DURATION)
    // 入宫年数为余数
    const left = taiyiLeft % TAIYI_DURATION === 0 ? TAIYI_DURATION : taiyiLeft % TAIYI_DURATION
    
    // 阳局起于乾1，阴局起于巽9
    const start = isSolar ? Taiyi.getIndexByTaiyiNum(1) : Taiyi.getIndexByTaiyiNum(9)
    const offset = isSolar ? palacesNum : palacesNum * (-1)
    
    let desIndex = start
    
    stage.travePalaceByTaiyiNum(start, offset, (item, index) => {
      // console.log(item.order, item.taiyiNum, item.description, item.pointer.taiyiNext, item.pointer.taiyiPrev)
      if (item.taiyiNum === 5) {
        // 直接跳过中5宫
        return true
      }
      if (index === palacesNum - 1) {
        // 遍历终点，记录下来
        desIndex = item.order
      }
    })
    const taiyiIndex = stage.palaces[desIndex].pointer.taiyi[0]
    
    // 找准位置后，太乙入宫
    Taiyi.setTaiyiSky(stage, 0, taiyiIndex, left)
    // 记录太乙落宫
    stage.taiyiPos = taiyiIndex
  }
  
  /*
    排布文昌
    排布方法：
    1. 积数 / 18 = 商 ...... 余
    2. 文昌起于武德(申), 按照 余 的数目，顺行十六神。
    3. 当行至阴德（乾宫）, 大武（坤宫）时，要数两次。
  */
  static setWenchang (stage) {
    // 阴阳局数
    const isSolar = stage.isSolar
    
    // 文昌除数
    const WENCHANG_DIVIDER = 18
    
    const offset = stage.taiyiNum % WENCHANG_DIVIDER === 0 ? WENCHANG_DIVIDER : stage.taiyiNum % WENCHANG_DIVIDER
    // 文昌固定起于武德
    const start = 11
    
    // 大武、阴德标准
    let doubleSign = false
    
    let desIndex = start
    stage.trave('taiyiPalaces', start, offset, (item, index) => {
      // console.log(item, item.order, offset)
      if (index === offset - 1) {
        desIndex = item.order
      }
    }, (item, index, list) => {
      if (item.order === 10 || item.order === 14) {
        // 大武、阴德，数两次
        if (!doubleSign) {
          doubleSign = true
          return item
        }
        else {
          doubleSign = false
          return list[item.pointer.go]
        }
      }
      return list[item.pointer.go]
    })
    
    // 找准位置后，文昌入宫
    Taiyi.setTaiyiSky(stage, 1, desIndex)
    // 记录文昌落宫
    stage.taiyiWenchangPos = desIndex
  }
  
  /*
    太乙求计神
    阴局子加寅位，阴局子加申位，逆行十二地支，每行一个地支，子向前数一位地支，数到时支(定局支)为止，此时到达的位置就是计神位置
  */
  static setJishen (stage) {
    // 阴阳局数
    const isSolar = stage.isSolar
    
    const offset = stage.keyGanzhi.zhi.index
    // 阴局子加寅位，阴局子加申位
    const start = isSolar ? 2 : 8
    const len = Zhi.zhiList.length
    const desZhiIndex = (start + len - offset) % len
    const zhiName = Zhi.zhiList[desZhiIndex]
    // 获取到太乙神的索引
    const desIndex = TaiyiGround.taiyiGroundSimList.indexOf(zhiName)
    
    // 找准位置后，计神入宫
    Taiyi.setTaiyiSky(stage, 4, desIndex)
    // 记录计神落宫
    stage.taiyiJishenPos = desIndex
  }
  
  /*
    太乙求始击
    1. 找到计神落宫后，统计计神顺行十六神到达和德(艮位)的步数。
    2. 从文昌落宫开始，顺行十六神，行走上一步统计出来的步数，到达位置就是始击落宫。
  */
  static setShiji (stage) {
    // 和德位置
    const desIndex = 2
    // 计神位置
    const srcIndex = stage.taiyiJishenPos
    
    const len = TaiyiGround.taiyiGroundList.length
    const offset = desIndex >= srcIndex ? desIndex - srcIndex : desIndex + len - srcIndex
    const taiyiDesIndex = (stage.taiyiWenchangPos + offset) % len
    
    // 找准位置后，始击入宫
    Taiyi.setTaiyiSky(stage, 5, taiyiDesIndex)
    // 记录始击落宫
    stage.taiyiShijiPos = taiyiDesIndex
  }
  
  /*
    太乙求算数
    isMain为true则求主算数，否则求客算数
    计算方法：
    1. 主算数的起算位置为文昌，客算数的起算位置为始击。
    2. 从起算位置开始，若该位置落在十六神的阳辰(子午卯酉和乾艮巽坤)，则初始算数为1，若落在阴辰(寅申巳亥和辰戌丑未)，初始算数为0。
    3. 顺行8宫，将初始算数与经过的所有宫位数相加，在下一宫即将数到太乙时停止，所得数即为对应的算数。
  */
  static getCountNum (stage, isMain = true) {
    // 主算数从文昌位置起算，客算数从始击位置起算
    const srcIndex = isMain ? stage.taiyiWenchangPos : stage.taiyiShijiPos
    // 阳辰、阴辰判定起始算数
    let count = srcIndex % 2 === 0 ? 1 : 0
    const startPalaceIndex = stage.taiyiPalaces[srcIndex].pointer.palace
    const taiyiPalaceIndex = stage.taiyiPalaces[stage.taiyiPos].pointer.palace
    if (startPalaceIndex === taiyiPalaceIndex) {
      // 和太乙落同宫，算数固定为1
      /* 
        @error 文昌和太乙落同宫，同十六神位时，算数为多少
        @error 文昌和太乙落同宫，但是文昌在阴辰，太乙在阳辰时，算数为多少
      */
      return 1
    }
    
    // 获取起始宫位
    const len = BaseStage.palacesBaguaList.length - 1
    let desIndex = 0
    stage.travePalaceByClock(startPalaceIndex, len, (item, index) => {
      // 累加算数
      count = count + item.taiyiNum
      if (item.pointer.go === taiyiPalaceIndex) {
        // 下一宫即将到太乙落宫时，结束遍历
        return false
      }
    })
    
    return count
  }
  
  /*
    根据算数获得大将和参将的落宫的索引
    isMain为true则求主算数，否则求客算数
    isSpe为true时，用新的方法穿太乙，否则用老方法
  */
  static getJiangPos (stage, isMain = true, isSpe = false) {
    /*
    if (isSpe) {
      // 新方法穿太乙
    }
    else {
      // 老方法穿太乙
    }
    */
    const count = isMain ? stage.taiyiMainNum : stage.taiyiSubNum
    // 暂时只写老方法
    let bigJiangPos = count % 10
    if (count % 10 === 0) {
      bigJiangPos = count % 9 === 0 ? 9 : count % 9
    }
    
    // 转换成宫位索引
    let bigJiangPosIndex = Taiyi.getIndexByTaiyiNum(bigJiangPos)
    // 注意中5宫寄宫
    const bigJiangDesIndex = Taiyi.fixedIndex(bigJiangPosIndex)
    // 转换成太乙十六神
    const bigDesIndex = stage.palaces[bigJiangDesIndex].pointer.taiyi[0]
    
    // 参将位置计算
    const subJiangPos = (bigJiangPos * 3) % 10
    let subJiangPosIndex = Taiyi.getIndexByTaiyiNum(subJiangPos)
    const subJiangDesIndex = Taiyi.fixedIndex(subJiangPosIndex)
    const subDesIndex = stage.palaces[subJiangDesIndex].pointer.taiyi[0]
    
    return {
      big: bigDesIndex,
      sub: subDesIndex,
      // 是否寄宫
      isSubExtra: subJiangDesIndex !== subJiangPosIndex,
      isBigExtra: bigJiangDesIndex !== bigJiangPosIndex
    }
  }
  
  /*
    太乙求大将、参将，
    isSpe为true时，用新的方法穿太乙，否则用老方法
    老方法穿太乙：
    1. 大将求法：当算数不被10整除时，取个位数字为落宫。否则，除以9取余数落宫
    2. 参将求法：大将所在宫位乘以3后，取个位数字为落宫。
  */
  static setJiang (stage, isSpe = false) {
    // 先算出主客算数
    stage.taiyiMainNum = Taiyi.getCountNum(stage, true)
    stage.taiyiSubNum = Taiyi.getCountNum(stage, false)
    
    /*
    if (isSpe) {
      // 新方法穿太乙
    }
    else {
      // 老方法穿太乙
    }
    */
    // 获取大将、参将的宫位索引
    const mainPos = Taiyi.getJiangPos(stage, true, isSpe)
    const subPos = Taiyi.getJiangPos(stage, false, isSpe)
    
    // 主大将
    Taiyi.setTaiyiSky(stage, 2, mainPos.big, null, mainPos.isBigExtra)
    // 主参将
    Taiyi.setTaiyiSky(stage, 3, mainPos.sub, null, mainPos.isSubExtra)
    // 客大将
    Taiyi.setTaiyiSky(stage, 6, subPos.big, null, subPos.isBigExtra)
    // 客参将
    Taiyi.setTaiyiSky(stage, 7, subPos.sub, null, subPos.isSubExtra)
  }
  
  /*
    排四神、天乙、地乙、飞符
    排法：
    1. 太乙数 / 36 = 商1 ...... 余1
    2. 余1 / 3 = 商 ...... 余，商 + 1 为所走宫数，余 为入宫年数
    3. 所走宫数按照 亥、午、寅、卯、辰、酉、申、子、巳、戌、未、丑 的顺序走，3年移一宫
    4. 四神起于亥，天乙起于酉，地乙起于巳，飞符起于辰
  */
  static setFourGods (stage) {
    // 四神、天乙、地乙、飞符除数
    const SISHEN_DIVIDER = 36
    // 入宫年数
    const SISHEN_DURATION = 3
    // 四神、天乙、地乙、飞符的特殊地支顺序
    const sishenZhiOrder = ['亥', '午', '寅', '卯', '辰', '酉', '申', '子', '巳', '戌', '未', '丑']
    
    const fourGodsIndexes = [8, 9, 10, 11]
    const fourGodsStart = ['亥', '酉', '巳', '辰']
    
    const len = sishenZhiOrder.length
    const godsLen = fourGodsIndexes.length
    for (let i = 0; i < godsLen; i++) {
      const godLeft = stage.taiyiNum % SISHEN_DIVIDER === 0 ? SISHEN_DIVIDER : stage.taiyiNum % SISHEN_DIVIDER
      // 移动宫数向上取整
      const palacesNum = Math.ceil(godLeft / SISHEN_DURATION)
      // 入宫年数为余数
      const left = godLeft % SISHEN_DURATION === 0 ? SISHEN_DURATION : godLeft % SISHEN_DURATION
      
      const startIndex = sishenZhiOrder.indexOf(fourGodsStart[i])
      const endIndex = (startIndex + palacesNum - 1) % len
      // console.log(startIndex, palacesNum, godLeft, endIndex, sishenZhiOrder[endIndex])
      const endTaiyiIndex = TaiyiGround.taiyiGroundSimList.indexOf(sishenZhiOrder[endIndex])
      
      // 确定位置后准备入宫
      Taiyi.setTaiyiSky(stage, fourGodsIndexes[i], endTaiyiIndex, left)
    }
  }
  
  /*
    排五福
    排法：
    1. 太乙数 / 225 = 商1 ...... 余1
    2. 余1 / 45 = 商 ...... 余，商 + 1 为所走宫数，余 为入宫年数
    3. 五福起乾宫，按乾、艮、巽、坤、中宫的顺序走，四十五数移一宫，当落中宫时，寄于乾宫
  */
  static setWufu (stage) {
    // 五福除数
    const WUFU_DIVIDER = 225
    // 入宫年数
    const WUFU_DURATION = 45
    // 入宫顺序
    const wufuOrder = ['乾', '艮', '巽', '坤', '中']
    
    // 五福入宫年数
    const godLeft = stage.taiyiNum % WUFU_DIVIDER === 0 ? WUFU_DIVIDER : stage.taiyiNum % WUFU_DIVIDER
    // 移动宫数向上取整
    const palacesNum = Math.ceil(godLeft / WUFU_DURATION)
    // 入宫年数为余数
    const left = godLeft % WUFU_DURATION === 0 ? WUFU_DURATION : godLeft % WUFU_DURATION
    
    const len = wufuOrder.length
    let desIndex = (palacesNum - 1) % len
    let isExtra = false
    if (desIndex === len - 1) {
      // 中宫寄于乾宫
      isExtra = true
      desIndex = 0
    }
    const desTaiyiIndex = TaiyiGround.taiyiGroundSimList.indexOf(wufuOrder[desIndex])
    
    // 确定位置后准备入宫
    Taiyi.setTaiyiSky(stage, 12, desTaiyiIndex, left, isExtra)
  }
 
  /*
    排小游
    1. 太乙数 / 24 = 商1 ...... 余1
    2. 余1 / 3 = 商 ...... 余，商 + 1 为所走宫数，余 为入宫年数
    3. 小游起1宫，顺加逆减，按照宫位数增减进行跳宫，不入中5宫。
  */
  static setXiaoyou (stage) {
    // 五福除数
    const XIAOYOU_DIVIDER = 24
    // 入宫年数
    const XIAOYOU_DURATION = 3
    // 小游1顺序
    const xiaoyouOrder = ['戌', '巳', '丑', '寅', '申', '未', '亥', '辰']
    
    // 小游入宫年数
    const godLeft = stage.taiyiNum % XIAOYOU_DIVIDER === 0 ? XIAOYOU_DIVIDER : stage.taiyiNum % XIAOYOU_DIVIDER
    // 移动宫数向上取整
    const palacesNum = Math.ceil(godLeft / XIAOYOU_DURATION)
    // 入宫年数为余数
    const left = godLeft % XIAOYOU_DURATION === 0 ? XIAOYOU_DURATION : godLeft % XIAOYOU_DURATION
    
    // 从戌位开始
    const len = xiaoyouOrder.length
    const desIndex = (palacesNum - 1) % len
    const desTaiyiIndex = TaiyiGround.taiyiGroundSimList.indexOf(xiaoyouOrder[desIndex])
    
    // 找准位置后，小游入宫
    Taiyi.setTaiyiSky(stage, 13, desTaiyiIndex, left)
  }
  
  /*
    排三基
    1. 太乙积数 / 除数1 = 商1 ...... 余1
    2. 余1 / 除2 = 商2 ...... 余2
    3. 商2 + 1 为所走步数，余2 为入宫年数，三基都顺行十二地支。
    4. 君基、臣基、民基的入宫年数(除数2)分别为30 3 1, 因此 除数1 分别为 360 36 12
    5. 君基、臣基、民基的其实地支位分别为 午 午 戌
  */
  static setThreeBases (stage) {
    // 君基、臣基、民基的入宫年数
    const durationList = [30, 3, 1]
    // 三基在地支的起始位置
    const startList = [6, 6, 10]
    const basesIndexes = [14, 15, 16]
    // 三基顺行地支十二神
    const len = Zhi.zhiList.length
    
    const baseLen = basesIndexes.length
    for (let i = 0; i < baseLen; i++) {
      const duration = durationList[i]
      
      const godLeft = stage.taiyiNum % (durationList[i] * len) === 0 ? durationList[i] * len : stage.taiyiNum % (durationList[i] * len)
      // 移动宫数向上取整
      const palacesNum = Math.ceil(godLeft / durationList[i])
      // 入宫年数为余数
      const left = godLeft % durationList[i] === 0 ? durationList[i] : godLeft % durationList[i]
      
      const zhiIndex = (startList[i] + palacesNum - 1) % len
      const desIndex = TaiyiGround.taiyiGroundSimList.indexOf(Zhi.zhiList[zhiIndex])
      
      if (durationList[i] === 1) {
        // 入宫年数为1年，不记录入宫年数
        Taiyi.setTaiyiSky(stage, basesIndexes[i], desIndex)
      }
      else {
        Taiyi.setTaiyiSky(stage, basesIndexes[i], desIndex, left)
      }
    }
  }
  
  /*
    太乙神煞入宫
    taiyiSkyIndex 太乙神煞索引
    taiyiIndex 入宫宫位索引
    yearNum 入宫年数，若为null则不记录入宫年数
    isExtra 是否为寄宫
  */
  static setTaiyiSky (stage, taiyiSkyIndex, taiyiIndex, yearNum = null, isExtra = false) {
    // console.log(taiyiSkyList[taiyiSkyIndex], taiyiIndex, stage.taiyiPalaces[taiyiIndex])
    let description = stage.taiyiPalaces[taiyiIndex].description + dictionary.TAIYI_SKY
    if (isExtra) {
      description = description + '(寄宫)'
    }
    
    let taiyiSky = new Base({
      index: taiyiSkyIndex,
      name: taiyiSkyList[taiyiSkyIndex],
      simName: taiyiSkySimList[taiyiSkyIndex],
      yinyang: taiyiSkyYinyangList[taiyiSkyIndex],
      wuxing: taiyiSkyWuxingList[taiyiSkyIndex],
      description: description
    })
    if (typeof yearNum === 'number' && yearNum) {
      // 记录入宫年数
      taiyiSky.yearNum = yearNum
    }
    stage.taiyiPalaces[taiyiIndex].ele.taiyiSky.push(taiyiSky)
  }
  
  
  // 根据太乙宫位数，获取太乙宫位索引
  static getIndexByTaiyiNum (num) {
    const index = Taiyi.palacesTaiyiNumList.indexOf(num)
    return index >= 0 ? index : 0
  }
  
  // 中五宫寄于乾一宫，获取修正后的索引
  static fixedIndex (index) {
    return index === CENTER_PALACE_INDEX ? EXTRA_PALACE_INDEX : index
  }
}

Object.assign(Taiyi, {
  
})

export default Taiyi